﻿using System;
using System.Reflection;
using MySql.Simple.Mapper.Finders;

namespace MySql.Simple.Mapper.Structures
{
    /// <summary>
    /// Represents a MySQL database on the server
    /// </summary>
    public class Database
    {
        // Private variables
        private readonly string name;
        private readonly Assembly assembly;
        private readonly Connection connection;

        /// <summary>
        /// Initializes a new instance of the <see cref="Database"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="assembly">The assembly.</param>
        public Database(string name, Assembly assembly)
        {
            this.name = name;
            this.assembly = assembly;
            
            connection = Connection.Create();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Database"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="assembly">The assembly.</param>
        /// <param name="connection">The connection.</param>
        public Database(string name, Assembly assembly, Connection connection)
        {
            this.name = name;
            this.assembly = assembly;
            this.connection = connection;
        }

        /// <summary>
        /// Ensures the database schema if correct.
        /// </summary>
        public void EnsureSchema()
        {
            var types = assembly.GetTypes();

            // Create/modify tables
            foreach (var type in types)
            {
                var tableName = TableNameFinder.Find(type);

                if (string.IsNullOrEmpty(tableName)) continue;

                var table = new Table(type, connection);

                if (table.Exists())
                {
                    table.CreateColumns();
                }
                else
                {
                    table.Create();
                }
            }

            // Add foreign keys & indicies
            foreach (var type in types)
            {
                var tableName = TableNameFinder.Find(type);

                if (string.IsNullOrEmpty(tableName)) continue;

                var table = new Table(type, connection);
                
                table.CreateForeignKeys();
                table.CreateIndicies();
            }
        }

        /// <summary>
        /// Empties all data from the database
        /// </summary>
        public void Empty()
        {
            var types = assembly.GetTypes();

            foreach (var type in types)
            {
                var tableName = TableNameFinder.Find(type);

                if (string.IsNullOrEmpty(tableName)) continue;

                var table = new Table(type, connection);

                if (table.Exists())
                {
                    table.Empty();
                }
            }
        }

        /// <summary>
        /// Gets the <see cref="Table"/> for the given type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public Table GetTable(Type type)
        {
            return new Table(type, connection);
        }

        /// <summary>
        /// Gets the <see cref="Table"/> for the given type.
        /// </summary>
        /// <returns></returns>
        public Table GetTable<T>() where T : new ()
        {
            return new Table<T>(connection);
        }
    }
}